Completed
Pull Request — patch_1-1-4 (#3191)
by Emanuele
13:25
created

elk_AdminIndex.showCurrentVersion   B

Complexity

Conditions 1
Paths 6

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 6
nop 0
dl 0
loc 43
rs 8.8571
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B 0 32 2
1
/*!
2
 * @name      ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
5
 *
6
 * This file contains code covered by:
7
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
8
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
9
 *
10
 * @version 1.1
11
 */
12
13
/**
14
 * Handle the JavaScript surrounding the admin and moderation center.
15
 */
16
17
/**
18
 * We like the globals cuz they is good to us
19
 */
20
21
/** global: previewTimeout, origText, valid, warningMessage, previewData, refreshPreviewCache, add_answer_template */
22
/** global: txt_add_another_answer, last_preview, txt_preview, elk_scripturl, txt_news_error_no_news, oThumbnails, elk_smiley_url */
23
/** global: db_vis, database_changes_area, elk_session_var, package_ftp_test, package_ftp_test_connection, package_ftp_test_failed */
24
/** global: onNewFolderReceived, elk_session_id, membersSwap, elk_images_url, maintain_members_choose, maintain_members_all */
25
/** global: reattribute_confirm, reattribute_confirm_email, reattribute_confirm_username, oModeratorSuggest, permission_profiles */
26
/** global: txt_save, txt_permissions_profile_rename, ajax_notification_cancel_text, txt_theme_remove_confirm, XMLHttpRequest */
27
/** global: theme_id, frames, editFilename, txt_ban_name_empty, txt_ban_restriction_empty, ElkInfoBar, txt_invalid_response */
28
/** global: feature_on_text, feature_off_text, core_settings_generic_error, startOptID, add_question_template, question_last_blank */
29
/** global: ourLanguageVersions, ourVersions, txt_add_another_answer, txt_permissions_commit, Image */
30
31
/**
32
 * Admin index class with the following methods
33
 * elk_AdminIndex(oOptions)
34
 * {
35
 *		public init()
36
 *		public loadAdminIndex()
37
 *		public setAnnouncements()
38
 *		public showCurrentVersion()
39
 *		public checkUpdateAvailable()
40
 * }
41
 *
42
 * @param {object} oOptions
43
 */
44
function elk_AdminIndex(oOptions)
45
{
46
	this.opt = oOptions;
47
	this.announcements = [];
48
	this.current = {};
49
	this.init_news = false;
50
	this.init();
51
}
52
53
// Initialize the admin index to handle announcement, current version and updates
54
elk_AdminIndex.prototype.init = function ()
55
{
56
	window.adminIndexInstanceRef = this;
57
58
	var fHandlePageLoaded = function () {
59
		window.adminIndexInstanceRef.loadAdminIndex();
60
	};
61
62
	addLoadEvent(fHandlePageLoaded);
63
};
64
65
elk_AdminIndex.prototype.loadAdminIndex = function ()
66
{
67
	// Load the current master and your version numbers.
68
	if (this.opt.bLoadVersions)
69
		this.showCurrentVersion();
70
71
	// Load the text box that says there's a new version available.
72
	if (this.opt.bLoadUpdateNotification)
73
		this.checkUpdateAvailable();
74
};
75
76
// Update the announcement container with news
77
elk_AdminIndex.prototype.setAnnouncement = function (announcement)
78
{
79
	var oElem = document.getElementById(this.opt.sAnnouncementContainerId),
80
		sMessages = this.init_news ? oElem.innerHTML : '',
81
		sMessage = '';
82
83
	sMessage = this.opt.sAnnouncementMessageTemplate.replace('%href%', announcement.html_url).replace('%subject%', announcement.name).replace('%time%', announcement.published_at.replace(/[TZ]/g, ' ')).replace('%message%', announcement.body).replace(/\n/g, '<br />').replace(/\r/g, '');
84
85
	oElem.innerHTML = sMessages + this.opt.sAnnouncementTemplate.replace('%content%', sMessage);
86
	this.init_news = true;
87
};
88
89
// Updates the current version container with the current version found in the repository
90
elk_AdminIndex.prototype.showCurrentVersion = function ()
91
{
92
	var oElkVersionContainer = document.getElementById(this.opt.slatestVersionContainerId),
93
		oinstalledVersionContainer = document.getElementById(this.opt.sinstalledVersionContainerId),
94
		sCurrentVersion = oinstalledVersionContainer.innerHTML,
95
		adminIndex = this,
96
		elkVersion = '???',
97
		verCompare = new elk_ViewVersions();
98
99
	$.getJSON('https://api.github.com/repos/elkarte/Elkarte/releases', {format: "json"},
100
	function(data, textStatus, jqXHR) {
0 ignored issues
show
Unused Code introduced by
The parameter textStatus is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter jqXHR is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
101
		var mostRecent = {},
102
			previous = {};
103
		adminIndex.current = adminIndex.normalizeVersion(sCurrentVersion);
104
105
		$.each(data, function(idx, elem) {
106
			// No drafts, thank you
107
			if (elem.draft)
108
				return;
109
110
			var release = adminIndex.normalizeVersion(elem.tag_name);
111
112
			if (!previous.hasOwnProperty('major') || verCompare.compareVersions(sCurrentVersion, elem.tag_name.replace('-', '').substring(1)))
113
			{
114
				// Using a preprelease? Then you may need to know a new one is out!
115
				if ((elem.prerelease && adminIndex.current.prerelease) || (!elem.prerelease))
116
				{
117
					previous = release;
118
					mostRecent = elem;
119
				}
120
			}
121
122
			// Load the text box containing the latest news items.
123
			if (adminIndex.opt.bLoadAnnouncements)
124
				adminIndex.setAnnouncement(elem);
125
		});
126
		elkVersion = mostRecent.name.replace(/elkarte/i, '').trim();
127
128
		oElkVersionContainer.innerHTML = elkVersion;
129
		if (verCompare.compareVersions(sCurrentVersion, elkVersion))
130
			oinstalledVersionContainer.innerHTML = adminIndex.opt.sVersionOutdatedTemplate.replace('%currentVersion%', sCurrentVersion);
131
	});
132
};
133
134
// Compare two different versions and return true if the firs is higher than the second
135
elk_AdminIndex.prototype.compareVersion = function (curVer, refVer)
136
{
137
	if (curVer.major > refVer.major)
138
		return true;
139
	else if (curVer.major < refVer.major)
140
		return false;
141
142
	if (curVer.minor > refVer.minor)
143
		return true;
144
	else if (curVer.minor < refVer.minor)
145
		return false;
146
147
	if (curVer.micro > refVer.micro)
148
		return true;
149
	else if (curVer.micro < refVer.micro)
150
		return false;
151
152
	if (curVer.prerelease)
153
	{
154
		if (curVer.nano > refVer.nano)
155
			return true;
156
		else if (curVer.nano < refVer.nano)
157
			return false;
158
	}
159
160
	return false;
161
};
162
163
// Split a string representing a version number into an object
164
elk_AdminIndex.prototype.normalizeVersion = function (sVersion)
165
{
166
	var splitVersion = sVersion.split(/[\s-]/),
167
	normalVersion = {
168
		major: 0,
169
		minor: 0,
170
		micro: 0,
171
		prerelease: false,
172
		status: 0,
173
		nano: 0
174
	},
175
	prerelease = false,
176
	aDevConvert = {'dev': 0, 'alpha': 1, 'beta': 2, 'rc': 3, 'stable': 4};
177
178
	for (var i = 0; i < splitVersion.length; i++)
179
	{
180
		if (splitVersion[i].toLowerCase() === 'elkarte')
181
			continue;
182
183
		if (splitVersion[i].substring(0, 3).toLowerCase() === 'dev' || splitVersion[i].substring(0, 5).toLowerCase() === 'alpha' || splitVersion[i].substring(0, 4).toLowerCase() === 'beta' || splitVersion[i].substring(0, 2).toLowerCase() === 'rc')
184
		{
185
			normalVersion.prerelease = true;
186
			prerelease = true;
187
188
			// the tag name comes with the number attached to the beta/rc
189
			if (splitVersion[i].indexOf('.') > 0)
190
			{
191
				var splitPre = splitVersion[i].split('.');
192
				normalVersion.nano = parseFloat(splitPre[1]);
193
				normalVersion.nano = parseFloat(splitVersion[i].substr(splitVersion[i].indexOf('.') + 1));
194
				normalVersion.status = aDevConvert[splitVersion[i].substr(0, splitVersion[i].indexOf('.')).toLowerCase()];
195
			}
196
		}
197
198
		// If we have passed a "beta" or an "RC" string, no need to go further
199
		if (prerelease)
200
		{
201
			// Only numbers and dots means a number
202
			if (splitVersion[i].replace(/[\d\.]/g, '') === '')
203
				normalVersion.nano = parseFloat(splitVersion[i]);
204
205
			continue;
206
		}
207
208
		// Likely from the tag
209
		if (splitVersion[i].substring(0, 1) === 'v')
210
			splitVersion[i] = splitVersion[i].substring(1);
211
212
		// Only numbers and dots means a number
213
		if (splitVersion[i].replace(/[\d\.]/g, '') === '')
214
		{
215
			var ver = splitVersion[i].split('.');
216
			normalVersion.major = parseInt(ver[0]);
217
			normalVersion.minor = parseInt(ver[1]);
218
			normalVersion.micro = ver.length > 2 ? parseInt(ver[2]) : 0;
219
		}
220
	}
221
	return normalVersion;
222
};
223
224
// Checks if a new version of ElkArte is available and if so updates the admin info box
225
elk_AdminIndex.prototype.checkUpdateAvailable = function ()
226
{
227
	if (!('ourUpdatePackage' in window))
228
		return;
229
230
	var oContainer = document.getElementById(this.opt.sUpdateNotificationContainerId);
231
232
	// Are we setting a custom title and message?
233
	var sTitle = 'ourUpdateTitle' in window ? window.ourUpdateTitle : this.opt.sUpdateNotificationDefaultTitle,
234
		sMessage = 'ourUpdateNotice' in window ? window.ourUpdateNotice : this.opt.sUpdateNotificationDefaultMessage;
235
236
	oContainer.innerHTML = this.opt.sUpdateNotificationTemplate.replace('%title%', sTitle).replace('%message%', sMessage);
237
238
	// Parse in the package download URL if it exists in the string.
239
	document.getElementById('update-link').href = this.opt.sUpdateNotificationLink.replace('%package%', window.ourUpdatePackage);
240
241
	// If we decide to override life into "red" mode, do it.
242
	if ('elkUpdateCritical' in window)
243
	{
244
		document.getElementById('update_title').style.backgroundColor = '#dd2222';
245
		document.getElementById('update_title').style.color = 'white';
246
		document.getElementById('update_message').style.backgroundColor = '#eebbbb';
247
		document.getElementById('update_message').style.color = 'black';
248
	}
249
};
250
251
/*
252
	elk_ViewVersions(oOptions)
253
	{
254
		public init()
255
		public loadViewVersions
256
		public swapOption(oSendingElement, sName)
257
		public compareVersions(sCurrent, sTarget)
258
		public determineVersions()
259
	}
260
*/
261
function elk_ViewVersions (oOptions)
262
{
263
	this.opt = oOptions;
264
	this.oSwaps = {};
265
	this.init();
266
}
267
268
// initialize the version checker
269
elk_ViewVersions.prototype.init = function ()
270
{
271
	// Load this on loading of the page.
272
	window.viewVersionsInstanceRef = this;
273
	var fHandlePageLoaded = function () {
274
		window.viewVersionsInstanceRef.loadViewVersions();
275
	};
276
	addLoadEvent(fHandlePageLoaded);
277
};
278
279
// Load all the file versions
280
elk_ViewVersions.prototype.loadViewVersions = function ()
281
{
282
	this.determineVersions();
283
};
284
285
elk_ViewVersions.prototype.swapOption = function (oSendingElement, sName)
286
{
287
	// If it is undefined, or currently off, turn it on - otherwise off.
288
	this.oSwaps[sName] = !(sName in this.oSwaps) || !this.oSwaps[sName];
289
	if (this.oSwaps[sName])
290
		$("#" + sName).show(300);
291
	else
292
		$("#" + sName).hide(300);
293
294
	// Unselect the link and return false.
295
	oSendingElement.blur();
296
297
	return false;
298
};
299
300
// compare a current and target version to determine if one is newer/older
301
elk_ViewVersions.prototype.compareVersions = function (sCurrent, sTarget)
302
{
303
	var aVersions = [],
304
		aParts = [],
0 ignored issues
show
Unused Code introduced by
The assignment to variable aParts seems to be never used. Consider removing it.
Loading history...
305
		aCompare = [sCurrent, sTarget],
306
		aDevConvert = {'dev': 0, 'alpha': 1, 'beta': 2, 'rc': 3};
307
308
	for (var i = 0; i < 2; i++)
309
	{
310
		// Clean the version and extract the version parts.
311
		var sClean = aCompare[i].toLowerCase().replace(/ /g, '').replace(/release candidate/g, 'rc');
312
		aParts = sClean.match(/(\d+)(?:\.(\d+|))?(?:\.)?(\d+|)(?:(alpha|beta|rc)\.*(\d+|)(?:\.)?(\d+|))?(?:(dev))?(\d+|)/);
313
314
		// No matches?
315
		if (aParts === null)
316
			return false;
317
318
		// Build an array of parts.
319
		aVersions[i] = [
320
			aParts[1] > 0 ? parseInt(aParts[1]) : 0,
321
			aParts[2] > 0 ? parseInt(aParts[2]) : 0,
322
			aParts[3] > 0 ? parseInt(aParts[3]) : 0,
323
			typeof(aParts[4]) === 'undefined' ? 'stable' : aDevConvert[aParts[4]],
324
			aParts[5] > 0 ? parseInt(aParts[5]) : 0,
325
			aParts[6] > 0 ? parseInt(aParts[6]) : 0,
326
			typeof(aParts[7]) !== 'undefined' ? 'dev' : ''
327
		];
328
	}
329
330
	// Loop through each category.
331
	for (i = 0; i < 7; i++)
332
	{
333
		// Is there something for us to calculate?
334
		if (aVersions[0][i] !== aVersions[1][i])
335
		{
336
			// Dev builds are a problematic exception.
337
			// (stable) dev < (stable) but (unstable) dev = (unstable)
338
			if (i === 3)
339
				return aVersions[0][i] < aVersions[1][i] ? !aVersions[1][6] : aVersions[0][6];
340
			else if (i === 6)
341
				return aVersions[0][6] ? aVersions[1][3] === 'stable' : false;
342
			// Otherwise a simple comparison.
343
			else
344
				return aVersions[0][i] < aVersions[1][i];
345
		}
346
	}
347
348
	// They are the same!
349
	return false;
350
};
351
352
// For each area of ElkArte, determine the current and installed versions
353
elk_ViewVersions.prototype.determineVersions = function ()
354
{
355
	var oHighYour = {
356
		sources: '??',
357
		admin: '??',
358
		controllers: '??',
359
		database: '??',
360
		subs: '??',
361
		'default': '??',
362
		Languages: '??',
363
		Templates: '??'
364
	};
365
	var oHighCurrent = {
366
		sources: '??',
367
		admin: '??',
368
		controllers: '??',
369
		database: '??',
370
		subs: '??',
371
		'default': '??',
372
		Languages: '??',
373
		Templates: '??'
374
	};
375
	var oLowVersion = {
376
		sources: false,
377
		admin: false,
378
		controllers: false,
379
		database: false,
380
		subs: false,
381
		'default': false,
382
		Languages: false,
383
		Templates: false
384
	};
385
386
	var sSections = [
387
		'sources',
388
		'admin',
389
		'controllers',
390
		'database',
391
		'subs',
392
		'default',
393
		'Languages',
394
		'Templates'
395
	];
396
397
	var sCurVersionType = '',
398
		sinstalledVersion,
399
		oSection,
400
		oSectionLink;
401
402
	for (var i = 0, n = sSections.length; i < n; i++)
403
	{
404
		// Collapse all sections.
405
		oSection = document.getElementById(sSections[i]);
406
407
		if (typeof(oSection) === 'object' && oSection !== null)
408
			oSection.style.display = 'none';
409
410
		// Make all section links clickable.
411
		oSectionLink = document.getElementById(sSections[i] + '-link');
412
		if (typeof(oSectionLink) === 'object' && oSectionLink !== null)
413
		{
414
			oSectionLink.instanceRef = this;
415
			oSectionLink.sSection = sSections[i];
416
			oSectionLink.onclick = function () {
417
				this.instanceRef.swapOption(this, this.sSection);
418
				return false;
419
			};
420
		}
421
	}
422
423
	if (!('ourVersions' in window))
424
		window.ourVersions = {};
425
426
	// for each file in the detailed-version.js
427
	for (var sFilename in window.ourVersions)
428
	{
429
		if (!window.ourVersions.hasOwnProperty(sFilename))
430
			continue;
431
432
		if (!document.getElementById('our' + sFilename))
433
			continue;
434
435
		sCurVersionType = '';
436
437
		sinstalledVersion = document.getElementById('your' + sFilename).innerHTML;
438
439
		for (var sVersionType in oLowVersion)
440
		{
441
			if (!oLowVersion.hasOwnProperty(sVersionType))
442
			{
443
				continue;
444
			}
445
446
			if (sFilename.substr(0, sVersionType.length) === sVersionType)
447
			{
448
				sCurVersionType = sVersionType;
449
				break;
450
			}
451
		}
452
453
		if (sCurVersionType === '')
454
			continue;
455
456
		// use compareVersion to determine which version is >< the other
457
		if (typeof(sCurVersionType) !== 'undefined')
458
		{
459
			if ((this.compareVersions(oHighYour[sCurVersionType], sinstalledVersion) || oHighYour[sCurVersionType] === '??') && !oLowVersion[sCurVersionType])
460
				oHighYour[sCurVersionType] = sinstalledVersion;
461
462
			if (this.compareVersions(oHighCurrent[sCurVersionType], ourVersions[sFilename]) || oHighCurrent[sCurVersionType] === '??')
463
				oHighCurrent[sCurVersionType] = ourVersions[sFilename];
464
465
			if (this.compareVersions(sinstalledVersion, ourVersions[sFilename]))
466
			{
467
				oLowVersion[sCurVersionType] = sinstalledVersion;
468
				document.getElementById('your' + sFilename).style.color = 'red';
469
			}
470
		}
471
		else if (this.compareVersions(sinstalledVersion, ourVersions[sFilename]))
472
			oLowVersion[sCurVersionType] = sinstalledVersion;
473
474
		document.getElementById('our' + sFilename).innerHTML = ourVersions[sFilename];
475
		document.getElementById('your' + sFilename).innerHTML = sinstalledVersion;
476
	}
477
478
	if (!('ourLanguageVersions' in window))
479
		window.ourLanguageVersions = {};
480
481
	for (sFilename in window.ourLanguageVersions)
482
	{
483
		for (i = 0; i < this.opt.aKnownLanguages.length; i++)
484
		{
485
			if (!document.getElementById('our' + sFilename + this.opt.aKnownLanguages[i]))
486
				continue;
487
488
			document.getElementById('our' + sFilename + this.opt.aKnownLanguages[i]).innerHTML = ourLanguageVersions[sFilename];
489
490
			sinstalledVersion = document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).innerHTML;
491
			document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).innerHTML = sinstalledVersion;
492
493
			if ((this.compareVersions(oHighYour.Languages, sinstalledVersion) || oHighYour.Languages === '??') && !oLowVersion.Languages)
494
				oHighYour.Languages = sinstalledVersion;
495
496
			if (this.compareVersions(oHighCurrent.Languages, ourLanguageVersions[sFilename]) || oHighCurrent.Languages === '??')
497
				oHighCurrent.Languages = ourLanguageVersions[sFilename];
498
499
			if (this.compareVersions(sinstalledVersion, ourLanguageVersions[sFilename]))
500
			{
501
				oLowVersion.Languages = sinstalledVersion;
502
				document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).style.color = 'red';
503
			}
504
		}
505
	}
506
507
	// Set the column titles based on the files each contain
508
	for (i = 0, n = sSections.length; i < n; i++)
509
	{
510
		if (sSections[i] === 'Templates')
511
			continue;
512
513
		document.getElementById('your' + sSections[i]).innerHTML = oLowVersion[sSections[i]] ? oLowVersion[sSections[i]] : oHighYour[sSections[i]];
514
		document.getElementById('our' + sSections[i]).innerHTML = oHighCurrent[sSections[i]];
515
		if (oLowVersion[sSections[i]])
516
			document.getElementById('your' + sSections[i]).style.color = 'red';
517
	}
518
519
	// Custom theme in use?
520
	if (document.getElementById('Templates'))
521
	{
522
		document.getElementById('yourTemplates').innerHTML = oLowVersion.Templates ? oLowVersion.Templates : oHighYour.Templates;
523
		document.getElementById('ourTemplates').innerHTML = oHighCurrent.Templates;
524
525
		if (oLowVersion.Templates)
526
			document.getElementById('yourTemplates').style.color = 'red';
527
	}
528
};
529
530
/**
531
 * Adds a new word container to the censored word list
532
 */
533
function addNewWord()
534
{
535
	setOuterHTML(document.getElementById('moreCensoredWords'), '<div class="censorWords"><input type="text" name="censor_vulgar[]" size="30" class="input_text" /> <i class="icon i-chevron-circle-right"></i> <input type="text" name="censor_proper[]" size="30" class="input_text" /><' + '/div><div id="moreCensoredWords"><' + '/div>');
536
}
537
538
/**
539
 * Will enable/disable checkboxes, according to if the BBC globally set or not.
540
 *
541
 * @param {string} section id of the container
542
 * @param {string} disable true or false
543
 */
544
function toggleBBCDisabled(section, disable)
545
{
546
	var elems = document.getElementById(section).getElementsByTagName('*');
547
548
	for (var i = 0; i < elems.length; i++)
549
	{
550
		if (typeof(elems[i].name) === "undefined" || (elems[i].name.substr((section.length + 1), (elems[i].name.length - 2 - (section.length + 1))) !== "enabledTags") || (elems[i].name.indexOf(section) !== 0))
551
			continue;
552
553
		elems[i].disabled = disable;
554
	}
555
	document.getElementById("bbc_" + section + "_select_all").disabled = disable;
556
}
557
558
/**
559
 * Keeps the input boxes display options appropriate for the options selected
560
 * when adding custom profile fields
561
 */
562
function updateInputBoxes()
563
{
564
	var curType = document.getElementById("field_type").value,
565
		privStatus = document.getElementById("private").value,
566
		stdText = ['text', 'textarea', 'email', 'url', 'color', 'date'],
567
		stdInput = ['text', 'email', 'url', 'color', 'date'],
568
		stdSelect = ['select'];
569
570
	var bIsStd = (stdInput.indexOf(curType) !== -1),
571
		bIsText = (stdText.indexOf(curType) !== -1),
572
		bIsSelect = (stdSelect.indexOf(curType) !== -1);
573
574
	// Only Text like fields can see a max length input
575
	document.getElementById("max_length_dt").style.display = bIsText ? "" : "none";
576
	document.getElementById("max_length_dd").style.display = bIsText ? "" : "none";
577
578
	// Textareas can get a row/col definition
579
	document.getElementById("dimension_dt").style.display = curType === "textarea" ? "" : "none";
580
	document.getElementById("dimension_dd").style.display = curType === "textarea" ? "" : "none";
581
582
	// Text like fields can be styled with bbc
583
	document.getElementById("bbc_dt").style.display = bIsText ? "" : "none";
584
	document.getElementById("bbc_dd").style.display = bIsText ? "" : "none";
585
586
	// And given defaults
587
	document.getElementById("defaultval_dt").style.display = bIsText ? "" : "none";
588
	document.getElementById("defaultval_dd").style.display = bIsText ? "" : "none";
589
590
	// Selects and radio can support a list of options
591
	document.getElementById("options_dt").style.display = curType === "select" || curType === "radio" ? "" : "none";
592
	document.getElementById("options_dd").style.display = curType === "select" || curType === "radio" ? "" : "none";
593
594
	// Checkboxes can have a default
595
	document.getElementById("default_dt").style.display = curType === "check" ? "" : "none";
596
	document.getElementById("default_dd").style.display = curType === "check" ? "" : "none";
597
598
	// Normal input boxes can use a validation mask as well
599
	document.getElementById("mask_dt").style.display = bIsStd ? "" : "none";
600
	document.getElementById("mask").style.display = bIsStd ? "" : "none";
601
602
	// And text and select fields are searchable
603
	document.getElementById("can_search_dt").style.display = bIsText || bIsSelect ? "" : "none";
604
	document.getElementById("can_search_dd").style.display = bIsText || bIsSelect ? "" : "none";
605
606
	// Moving to a non searchable field, be sure searchable is unselected.
607
	if (!bIsText && !bIsSelect)
608
		document.getElementById("can_search_dd").checked = false;
609
610
	// Using regex in the mask, give them a place to supply the regex
611
	document.getElementById("regex_div").style.display = bIsStd && document.getElementById("mask").value === "regex" ? "" : "none";
612
	document.getElementById("display").disabled = false;
613
614
	// Cannot show this on the topic
615
	if (curType === "textarea" || privStatus >= 2)
616
	{
617
		document.getElementById("display").checked = false;
618
		document.getElementById("display").disabled = true;
619
	}
620
}
621
622
/**
623
 * Used to add additional radio button options when editing a custom profile field
624
 */
625
function addOption()
626
{
627
	setOuterHTML(document.getElementById("addopt"), '<p><input type="radio" name="default_select" value="' + startOptID + '" id="' + startOptID + '" /><input type="text" name="select_option[' + startOptID + ']" value="" class="input_text" /></p><span id="addopt"></span>');
628
	startOptID++;
629
}
630
631
/**
632
 * Adds another question to the registration page
633
 */
634
function addAnotherQuestion()
635
{
636
	var placeHolder = document.getElementById('add_more_question_placeholder');
637
638
	setOuterHTML(placeHolder, add_question_template.easyReplace({
639
		question_last_blank: question_last_blank,
640
		setup_verification_add_more_answers: txt_add_another_answer
641
	}));
642
643
	question_last_blank++;
644
}
645
646
/**
647
 * Every question should have an answer, even if its a lie
648
 *
649
 * @param {HTMLElement} elem
650
 * @param {string} question_name
651
 */
652
function addAnotherAnswer(elem, question_name)
653
{
654
	setOuterHTML(elem, add_answer_template.easyReplace({
655
		question_last_blank: question_name,
656
		setup_verification_add_more_answers: txt_add_another_answer
657
	}));
658
}
659
660
/**
661
 * Used to add new search engines to the known list
662
 *
663
 * @param {string} txt_name
664
 * @param {string} txt_url
665
 * @param {string} txt_word_sep
666
 */
667
function addAnotherSearch(txt_name, txt_url, txt_word_sep)
668
{
669
	var placeHolder = document.getElementById('add_more_searches'),
670
		newDT = document.createElement("dt"),
671
		newInput = document.createElement("input"),
672
		newLabel = document.createElement("label"),
673
		newDD = document.createElement("dd");
674
675
	newInput.name = "engine_name[]";
676
	newInput.type = "text";
677
	newInput.className = "input_text";
678
	newInput.size = "50";
679
	newInput.setAttribute("class", "verification_question");
680
681
	// Add the label and input box to the DOM
682
	newLabel.textContent = txt_name + ': ';
683
	newLabel.appendChild(newInput);
684
	newDT.appendChild(newLabel);
685
686
	// Next input box
687
	newInput = document.createElement("input");
688
	newInput.name = "engine_url[]";
689
	newInput.type = "text";
690
	newInput.className = "input_text";
691
	newInput.size = "35";
692
	newInput.setAttribute("class", "input_text verification_answer");
693
694
	// Add the new label and input box
695
	newLabel = document.createElement("label");
696
	newLabel.textContent = txt_url + ': ';
697
	newLabel.appendChild(newInput);
698
	newDD.appendChild(newLabel);
699
	newDD.appendChild(document.createElement("br"));
700
701
	// Rinse and repeat
702
	newInput = document.createElement("input");
703
	newInput.name = "engine_separator[]";
704
	newInput.type = "text";
705
	newInput.className = "input_text";
706
	newInput.size = "5";
707
	newInput.setAttribute("class", "input_text verification_answer");
708
709
	newLabel = document.createElement("label");
710
	newLabel.textContent = txt_word_sep + ': ';
711
	newLabel.appendChild(newInput);
712
	newDD.appendChild(newLabel);
713
714
	placeHolder.parentNode.insertBefore(newDT, placeHolder);
715
	placeHolder.parentNode.insertBefore(newDD, placeHolder);
716
}
717
718
/**
719
 * News admin page
720
 */
721
function addAnotherNews()
722
{
723
	var last = $("#list_news_lists_last"),
724
		$new_item = last.clone();
725
726
	last_preview++;
727
	$new_item.attr('id', 'list_news_lists_' + last_preview);
728
	$new_item.find('textarea').attr('id', 'data_' + last_preview);
729
	$new_item.find('#preview_last').attr('id', 'preview_' + last_preview);
730
	$new_item.find('#box_preview_last').attr('id', 'box_preview_' + last_preview);
731
732
	last.before($new_item);
733
	$new_item.toggle();
734
	make_preview_btn(last_preview);
735
}
736
737
/**
738
 * Makes the preview button when in manage news
739
 *
740
 * @param {string} preview_id
741
 */
742
function make_preview_btn (preview_id)
743
{
744
	var $id = $("#preview_" + preview_id);
745
746
	$id.text(txt_preview).on('click', function () {
747
		$.ajax({
748
			type: "POST",
749
			url: elk_scripturl + "?action=xmlpreview;xml",
750
			data: {item: "newspreview", news: $("#data_" + preview_id).val()},
751
			context: document.body
752
		})
753
		.done(function(request) {
754
			if ($(request).find("error").text() === '')
755
				$(document).find("#box_preview_" + preview_id).html($(request).text());
756
			else
757
				$(document).find("#box_preview_" + preview_id).text(txt_news_error_no_news);
758
		});
759
	});
760
761
	if (!$id.parent().hasClass('linkbutton_right'))
762
		$id.wrap('<a class="linkbutton_right" href="javascript:void(0);"></a>');
763
}
764
765
/**
766
 * Used by manage themes to show the thumbnail of the theme variant chosen
767
 *
768
 * @param {string} sVariant
769
 */
770
function changeVariant(sVariant)
771
{
772
	document.getElementById('variant_preview').src = oThumbnails[sVariant];
773
}
774
775
/**
776
 * The idea here is simple: don't refresh the preview on every keypress, but do refresh after they type.
777
 *
778
 * @returns {undefined}
779
 */
780
function setPreviewTimeout()
781
{
782
	if (previewTimeout)
783
	{
784
		window.clearTimeout(previewTimeout);
785
		previewTimeout = null;
786
	}
787
788
	previewTimeout = window.setTimeout(function() {refreshPreview(true); previewTimeout = null;}, 500);
789
}
790
791
/**
792
 * Used in manage paid subscriptions to show the fixed duration panel or
793
 * the variable duration panel, based on which radio button is selected
794
 *
795
 * @param {type} toChange
796
 */
797
function toggleDuration(toChange)
0 ignored issues
show
Unused Code introduced by
The parameter toChange is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
798
{
799
	$("#fixed_area").slideToggle(300);
800
	$("#flexible_area").slideToggle(300);
801
}
802
803
/**
804
 * Used when editing the search weights for results, calculates the overall total weight
805
 */
806
function calculateNewValues()
807
{
808
	var total = 0;
809
	for (var i = 1; i <= 7; i++)
810
	{
811
		total += parseInt(document.getElementById('weight' + i + '_val').value);
812
	}
813
814
	document.getElementById('weighttotal').innerHTML = total;
815
	for (i = 1; i <= 7; i++)
816
	{
817
		document.getElementById('weight' + i).innerHTML = (Math.round(1000 * parseInt(document.getElementById('weight' + i + '_val').value) / total) / 10) + '%';
818
	}
819
}
820
821
/**
822
 * Toggle visibility of add smile image source options
823
 */
824
function switchType()
825
{
826
	document.getElementById("ul_settings").style.display = document.getElementById("method-existing").checked ? "none" : "block";
827
	document.getElementById("ex_settings").style.display = document.getElementById("method-upload").checked ? "none" : "block";
828
}
829
830
/**
831
 * Toggle visibility of smiley set should the user want different images in a set (add smiley)
832
 */
833
function swapUploads()
834
{
835
	document.getElementById("uploadMore").style.display = document.getElementById("uploadSmiley").disabled ? "none" : "block";
836
	document.getElementById("uploadSmiley").disabled = !document.getElementById("uploadSmiley").disabled;
837
}
838
839
/**
840
 * Close the options that should not be visible for adding a smiley
841
 *
842
 * @param {string} element
843
 */
844
function selectMethod(element)
845
{
846
	document.getElementById("method-existing").checked = element !== "upload";
847
	document.getElementById("method-upload").checked = element === "upload";
848
}
849
850
/**
851
 * Updates the smiley preview to show the current one chosen
852
 */
853
function updatePreview()
854
{
855
	var currentImage = document.getElementById("preview");
856
	currentImage.src = elk_smiley_url + "/" + document.forms.smileyForm.set.value + "/" + document.forms.smileyForm.smiley_filename.value;
857
}
858
859
/**
860
 * Used in package manager to swap the visibility of database changes
861
 */
862
function swap_database_changes()
863
{
864
	db_vis = !db_vis;
865
	database_changes_area.style.display = db_vis ? "" : "none";
866
867
	return false;
868
}
869
870
/**
871
 * Test the given form credentials to test if an FTP connection can be made
872
 */
873
function testFTP()
874
{
875
	ajax_indicator(true);
876
877
	// What we need to post.
878
	var oPostData = {
879
		0: "ftp_server",
880
		1: "ftp_port",
881
		2: "ftp_username",
882
		3: "ftp_password",
883
		4: "ftp_path"
884
	};
885
886
	var sPostData = "";
887
	for (var i = 0; i < 5; i++)
888
		sPostData = sPostData + (sPostData.length === 0 ? "" : "&") + oPostData[i] + "=" + document.getElementById(oPostData[i]).value.php_urlencode();
889
890
	// Post the data out.
891
	sendXMLDocument(elk_prepareScriptUrl(elk_scripturl) + 'action=admin;area=packages;sa=ftptest;xml;' + elk_session_var + '=' + elk_session_id, sPostData, testFTPResults);
892
}
893
894
/**
895
 * Generate a "test ftp" button.
896
 */
897
function generateFTPTest()
898
{
899
	// Don't ever call this twice!
900
	if (generatedButton)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable generatedButton is declared in the current environment, consider using typeof generatedButton === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
901
		return false;
902
903
	generatedButton = true;
0 ignored issues
show
Bug introduced by
The variable generatedButton seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.generatedButton.
Loading history...
904
905
	// No XML?
906
	if (!document.getElementById("test_ftp_placeholder") && !document.getElementById("test_ftp_placeholder_full"))
907
		return false;
908
909
	// create our test button to call testFTP on click
910
	var ftpTest = document.createElement("input");
911
	ftpTest.type = "button";
912
	ftpTest.className = "submit";
913
	ftpTest.onclick = testFTP;
914
915
	// Set the button value based on which form we are on
916
	if (document.getElementById("test_ftp_placeholder"))
917
	{
918
		ftpTest.value = package_ftp_test;
919
		document.getElementById("test_ftp_placeholder").appendChild(ftpTest);
920
	}
921
	else
922
	{
923
		ftpTest.value = package_ftp_test_connection;
924
		document.getElementById("test_ftp_placeholder_full").appendChild(ftpTest);
925
	}
926
927
	return true;
928
}
929
930
/**
931
 * Callback function of the testFTP function
932
 *
933
 * @param {type} oXMLDoc
934
 */
935
function testFTPResults(oXMLDoc)
936
{
937
	ajax_indicator(false);
938
939
	// This assumes it went wrong!
940
	var wasSuccess = false,
941
		message = package_ftp_test_failed,
942
		results = oXMLDoc.getElementsByTagName('results')[0].getElementsByTagName('result');
943
944
	// Results show we were a success
945
	if (results.length > 0)
946
	{
947
		if (parseInt(results[0].getAttribute('success')) === 1)
948
			wasSuccess = true;
949
		message = results[0].firstChild.nodeValue;
950
	}
951
952
	// place the informative box on screen so the user knows if things went well or poorly
953
	document.getElementById("ftp_error_div").style.display = "";
954
	document.getElementById("ftp_error_div").className = wasSuccess ? "successbox" : "errorbox";
955
	document.getElementById("ftp_error_message").innerHTML = message;
956
}
957
958
/**
959
 * Part of package manager, expands a folders contents to show
960
 * permission levels of files it contains.
961
 * Will use an ajax call to get any permissions it has not loaded
962
 *
963
 * @param {type} folderIdent
964
 * @param {type} folderReal
965
 */
966
function expandFolder(folderIdent, folderReal)
967
{
968
	// See if it already exists.
969
	var possibleTags = document.getElementsByTagName("tr");
970
	var foundOne = false;
971
972
	for (var i = 0; i < possibleTags.length; i++)
973
	{
974
		if (possibleTags[i].id.indexOf("content_" + folderIdent + ":-:") === 0)
975
		{
976
			possibleTags[i].style.display = possibleTags[i].style.display === "none" ? "" : "none";
977
			foundOne = true;
978
		}
979
	}
980
981
	// Got something then we're done.
982
	if (foundOne)
983
	{
984
		return false;
985
	}
986
987
	// Otherwise we need to get the wicked thing.
988
	ajax_indicator(true);
989
	getXMLDocument(elk_prepareScriptUrl(elk_scripturl) + 'action=admin;area=packages;onlyfind=' + folderReal.php_urlencode() + ';sa=perms;xml;' + elk_session_var + '=' + elk_session_id, onNewFolderReceived);
990
991
	return false;
992
}
993
994
/**
995
 * Wrapper function to call expandFolder
996
 */
997
function dynamicExpandFolder()
998
{
999
	expandFolder(this.ident, this.path);
1000
1001
	return false;
1002
}
1003
1004
/**
1005
 * Used when edit the boards and groups access to them
1006
 *
1007
 * @param {type} operation
1008
 * @param {type} brd_list
1009
 */
1010
function select_in_category(operation, brd_list)
1011
{
1012
	for (var brd in brd_list) {
1013
		if (!brd_list.hasOwnProperty(brd))
1014
			continue;
1015
1016
		document.getElementById(operation + '_brd' + brd_list[brd]).checked = true;
1017
	}
1018
}
1019
1020
/**
1021
 * Server Settings > Caching, toggles input fields on/off as appropriate for
1022
 * a given cache engine selection
1023
 */
1024
$(function() {
1025
	$('#cache_accelerator').change(function() {
1026
		// Hide all the settings
1027
		$('#cache_accelerator').find('option').each(function() {
1028
			$('[id^=' + $(this).val() + '_]').hide();
1029
		});
1030
1031
		// Show the settings of the selected engine
1032
		$('[id^=' + $(this).val() + '_]').show();
1033
	})
1034
	// Trigger a change action so that the form is properly initialized
1035
	.change();
1036
});
1037
1038
/**
1039
 * Server Settings > Caching, toggles input fields on/off as appropriate for
1040
 * a given cache engine selection
1041
 */
1042
function toggleCache ()
1043
{
1044
	var memcache = $('#cache_memcached').parent(),
1045
		cachedir = $('#cachedir').parent(),
1046
		cacheuid = $('#cache_uid').parent(),
1047
		cachepassword = $('#cache_password').parent(),
1048
		cacheconfirm = $('#cache_password_confirm').parent();
1049
1050
	// Show the memcache server box only if memcache has been selected
1051
	if (cache_type.value.substr(0, 8) !== "memcache")
0 ignored issues
show
Bug introduced by
The variable cache_type seems to be never declared. If this is a global, consider adding a /** global: cache_type */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1052
	{
1053
		memcache.slideUp();
1054
		memcache.prev().slideUp(100);
1055
	}
1056
	else
1057
	{
1058
		memcache.slideDown();
1059
		memcache.prev().slideDown(100);
1060
	}
1061
1062
	// don't show the directory if its not filebased
1063
	if (cache_type.value === "filebased")
1064
	{
1065
		cachedir.slideDown();
1066
		cachedir.prev().slideDown(100);
1067
	}
1068
	else
1069
	{
1070
		cachedir.slideUp(100);
1071
		cachedir.prev().slideUp(100);
1072
	}
1073
1074
	// right now only xcache needs the uid/password
1075
	if (cache_type.value === "xcache")
1076
	{
1077
		cacheuid.slideDown(100);
1078
		cacheuid.prev().slideDown(100);
1079
		cachepassword.slideDown(100);
1080
		cachepassword.prev().slideDown(100);
1081
		cacheconfirm.slideDown(100);
1082
		cacheconfirm.prev().slideDown(100);
1083
	}
1084
	else
1085
	{
1086
		cacheuid.slideUp(100);
1087
		cacheuid.prev().slideUp(100);
1088
		cachepassword.slideUp(100);
1089
		cachepassword.prev().slideUp(100);
1090
		cacheconfirm.slideUp(100);
1091
		cacheconfirm.prev().slideUp(100);
1092
	}
1093
}
1094
1095
/**
1096
 * Hides local / subdomain cookie options in the ACP based on selected choices
1097
 * area=serversettings;sa=cookie
1098
 */
1099
function hideGlobalCookies()
1100
{
1101
	var bUseLocal = document.getElementById("localCookies").checked,
1102
		bUseGlobal = !bUseLocal && document.getElementById("globalCookies").checked;
1103
1104
	// Show/Hide the areas based on what they have chosen
1105
	if (!bUseLocal)
1106
	{
1107
		$("#setting_globalCookies").parent().slideDown();
1108
		$("#globalCookies").parent().slideDown();
1109
	}
1110
	else
1111
	{
1112
		$("#setting_globalCookies").parent().slideUp();
1113
		$("#globalCookies").parent().slideUp();
1114
	}
1115
1116
	// Global selected means we need to reveal the domain input box
1117
	if (bUseGlobal)
1118
	{
1119
		$("#setting_globalCookiesDomain").closest("dt").slideDown();
1120
		$("#globalCookiesDomain").closest("dd").slideDown();
1121
	}
1122
	else
1123
	{
1124
		$("#setting_globalCookiesDomain").closest("dt").slideUp();
1125
		$("#globalCookiesDomain").closest("dd").slideUp();
1126
	}
1127
}
1128
1129
/**
1130
 * Attachments Settings
1131
 */
1132
function toggleSubDir ()
1133
{
1134
	var auto_attach = document.getElementById('automanage_attachments'),
1135
		use_sub_dir = document.getElementById('use_subdirectories_for_attachments'),
1136
		dir_elem = document.getElementById('basedirectory_for_attachments');
1137
1138
	use_sub_dir.disabled = !Boolean(auto_attach.selectedIndex);
1139
	if (use_sub_dir.disabled)
1140
	{
1141
		$(use_sub_dir).slideUp();
1142
		$('#setting_use_subdirectories_for_attachments').parent().slideUp();
1143
1144
		$(dir_elem).slideUp();
1145
		$('#setting_basedirectory_for_attachments').parent().slideUp();
1146
	}
1147
	else
1148
	{
1149
		$(use_sub_dir).slideDown();
1150
		$('#setting_use_subdirectories_for_attachments').parent().slideDown();
1151
1152
		$(dir_elem).slideDown();
1153
		$('#setting_basedirectory_for_attachments').parent().slideDown();
1154
	}
1155
		toggleBaseDir();
1156
}
1157
1158
/**
1159
 * Called by toggleSubDir as part of manage attachments
1160
 */
1161
function toggleBaseDir ()
1162
{
1163
	var auto_attach = document.getElementById('automanage_attachments'),
1164
		sub_dir = document.getElementById('use_subdirectories_for_attachments'),
1165
		dir_elem = document.getElementById('basedirectory_for_attachments');
1166
1167
	if (auto_attach.selectedIndex === 0)
1168
		dir_elem.disabled = 1;
1169
	else
1170
		dir_elem.disabled = !sub_dir.checked;
1171
}
1172
1173
1174
/**
1175
 * Called from purgeinactive users maintenance task, used to show or hide
1176
 * the membergroup list.  If collapsed will select all the member groups if expanded
1177
 * unselect them so the user can choose.
1178
 */
1179
function swapMembers()
1180
{
1181
	var membersForm = document.getElementById('membersForm');
1182
1183
	// Make it close smoothly
1184
	$("#membersPanel").slideToggle(300);
1185
1186
	membersSwap = !membersSwap;
1187
	document.getElementById("membersIcon").src = elk_images_url + (membersSwap ? "/selected_open.png" : "/selected.png");
1188
	document.getElementById("membersText").innerHTML = membersSwap ? maintain_members_choose : maintain_members_all;
1189
1190
	// Check or uncheck them all based on if we are expanding or collasping the area
1191
	for (var i = 0; i < membersForm.length; i++)
1192
	{
1193
		if (membersForm.elements[i].type.toLowerCase() === "checkbox")
1194
			membersForm.elements[i].checked = !membersSwap;
1195
	}
1196
1197
	return false;
1198
}
1199
1200
/**
1201
 * Called from reattribute member posts to build the confirm message for the action
1202
 * Keeps the action button (reattribute) disabled until all necessary fields have been filled
1203
 */
1204
function checkAttributeValidity()
1205
{
1206
	origText = reattribute_confirm;
1207
	valid = true;
1208
1209
	// Do all the fields!
1210
	if (!document.getElementById('to').value)
1211
		valid = false;
1212
1213
	warningMessage = origText.replace(/%member_to%/, document.getElementById('to').value);
1214
1215
	// Using email address to find the member
1216
	if (document.getElementById('type_email').checked)
1217
	{
1218
		if (!document.getElementById('from_email').value)
1219
			valid = false;
1220
1221
		warningMessage = warningMessage.replace(/%type%/, '', reattribute_confirm_email).replace(/%find%/, document.getElementById('from_email').value);
1222
	}
1223
	// Or the user name
1224
	else
1225
	{
1226
		if (!document.getElementById('from_name').value)
1227
			valid = false;
1228
1229
		warningMessage = warningMessage.replace(/%type%/, '', reattribute_confirm_username).replace(/%find%/, document.getElementById('from_name').value);
1230
	}
1231
1232
	document.getElementById('do_attribute').disabled = !valid;
1233
1234
	// Keep checking for a valid form so we can activate the submit button
1235
	setTimeout(function() {checkAttributeValidity();}, 500);
1236
1237
	return valid;
1238
}
1239
1240
/**
1241
 * Enable/disable fields when transferring attachments
1242
 *
1243
 * @returns {undefined}
1244
 */
1245
function transferAttachOptions()
1246
{
1247
	var autoSelect = document.getElementById("auto"),
1248
		autoValue = parseInt(autoSelect.options[autoSelect.selectedIndex].value, 10),
1249
		toSelect = document.getElementById("to"),
1250
		toValue = parseInt(toSelect.options[toSelect.selectedIndex].value, 10);
1251
1252
		toSelect.disabled = autoValue !== 0;
1253
		autoSelect.disabled = toValue !== 0;
1254
}
1255
1256
/**
1257
 * Updates the move confirmation text so its descriptive for the current items
1258
 * being moved.
1259
 *
1260
 * @param {string} confirmText
1261
 */
1262
function confirmMoveTopics(confirmText)
1263
{
1264
	var from = document.getElementById('id_board_from'),
1265
		to = document.getElementById('id_board_to');
1266
1267
	if (from.options[from.selectedIndex].disabled || from.options[to.selectedIndex].disabled)
1268
		return false;
1269
1270
	return confirm(confirmText.replace(/%board_from%/, from.options[from.selectedIndex].text.replace(/^\u2003+\u27A4/, '')).replace(/%board_to%/, to.options[to.selectedIndex].text.replace(/^\u2003+\u27A4/, '')));
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1271
}
1272
1273
/**
1274
 * Hide the search methods area if using sphinx(ql) search
1275
 */
1276
function showhideSearchMethod()
1277
{
1278
	var searchSphinxQl = document.getElementById('search_index_sphinxql').checked,
1279
		searchSphinx = document.getElementById('search_index_sphinx').checked,
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1280
		searchhide = searchSphinxQl || searchSphinx,
1281
		searchMethod = $('#search_method');
1282
1283
	if (searchhide)
1284
		searchMethod.slideUp();
1285
	else
1286
		searchMethod.slideDown();
1287
}
1288
1289
/**
1290
 * Used in manageFeatures to show / hide custom level input elements based on the checkbox choices
1291
 * Will show or hide the jquery and jqueryui custom input fields for admins that like to roll the dice
1292
 */
1293
function showhideJqueryOptions()
1294
{
1295
	var jqBase = document.getElementById('jquery_default').checked,
1296
		jqUi = document.getElementById('jqueryui_default').checked,
1297
		jqBase_val = $('#jquery_version'),
1298
		jqUi_val = $('#jqueryui_version');
1299
1300
	// Show the jquery custom level box only if the option has been selected
1301
	// yes the dt dd stuff makes it this ugly
1302
	if (jqBase === false)
1303
	{
1304
		// dd and the dt
1305
		jqBase_val.parent().slideUp();
1306
		jqBase_val.parent().prev().slideUp();
1307
	}
1308
	else
1309
	{
1310
		jqBase_val.parent().slideDown();
1311
		jqBase_val.parent().prev().slideDown();
1312
	}
1313
1314
	// And the same for the UI areas as well
1315
	if (jqUi === false)
1316
	{
1317
		// The parent is the dd and the sibling is its dt
1318
		jqUi_val.parent().slideUp();
1319
		jqUi_val.parent().prev().slideUp();
1320
	}
1321
	else
1322
	{
1323
		jqUi_val.parent().slideDown();
1324
		jqUi_val.parent().prev().slideDown();
1325
	}
1326
}
1327
1328
/**
1329
 * Used in manageMembergroups to enable disable form elements based on allowable choices
1330
 * If post based group is selected, it will disable moderation selection, visibility, group description
1331
 * and enable post count input box
1332
 *
1333
 * @param {boolean} isChecked
1334
 */
1335
function swapPostGroup(isChecked)
1336
{
1337
	var min_posts_text = document.getElementById('min_posts_text'),
1338
		group_desc_text = document.getElementById('group_desc_text'),
1339
		group_hidden_text = document.getElementById('group_hidden_text'),
1340
		group_moderators_text = document.getElementById('group_moderators_text');
1341
1342
	document.forms.groupForm.min_posts.disabled = !isChecked;
1343
	min_posts_text.style.color = isChecked ? "" : "#888";
1344
1345
	document.forms.groupForm.group_desc_input.disabled = isChecked;
1346
	group_desc_text.style.color = !isChecked ? "" : "#888";
1347
1348
	document.forms.groupForm.group_hidden_input.disabled = isChecked;
1349
	group_hidden_text.style.color = !isChecked ? "" : "#888";
1350
1351
	document.forms.groupForm.group_moderators.disabled = isChecked;
1352
	group_moderators_text.style.color = !isChecked ? "" : "#888";
1353
1354
	// Disable the moderator autosuggest box as well
1355
	if (typeof(oModeratorSuggest) !== 'undefined')
1356
		oModeratorSuggest.oTextHandle.disabled = !!isChecked;
1357
}
1358
1359
/**
1360
 * Handles the AJAX preview of the warning templates
1361
 */
1362
function ajax_getTemplatePreview()
1363
{
1364
	$.ajax({
1365
		type: "POST",
1366
		url: elk_scripturl + '?action=xmlpreview;xml',
1367
		data: {
1368
			item: "warning_preview",
1369
			title: $("#template_title").val(),
1370
			body: $("#template_body").val(),
1371
			user: $('input[name="u"]').attr("value")
1372
		},
1373
		context: document.body
1374
	})
1375
	.done(function(request) {
1376
		$("#box_preview").css({display:"block"});
1377
		$("#template_preview").html($(request).find('body').text());
1378
1379
		var $_errors = $("#errors");
1380
		if ($(request).find("error").text() !== '')
1381
		{
1382
			$_errors.css({display:"block"});
1383
1384
			var errors_html = '',
1385
			errors = $(request).find('error').each(function() {
0 ignored issues
show
Unused Code introduced by
The variable errors seems to be never used. Consider removing it.
Loading history...
1386
				errors_html += $(this).text() + '<br />';
1387
			});
1388
1389
			$(document).find("#error_list").html(errors_html);
1390
			$('html, body').animate({ scrollTop: $_errors.offset().top }, 'slow');
1391
		}
1392
		else
1393
		{
1394
			$_errors.css({display:"none"});
1395
			$("#error_list").html('');
1396
			$('html, body').animate({ scrollTop: $("#box_preview").offset().top }, 'slow');
1397
		}
1398
1399
		return false;
1400
	});
1401
1402
	return false;
1403
}
1404
1405
/**
1406
 * Sets up all the js events for edit and save board-specific permission
1407
 * profiles
1408
 */
1409
function initEditProfileBoards()
1410
{
1411
	$('.edit_all_board_profiles').on('click', function(e) {
1412
		e.preventDefault();
1413
1414
		$('.edit_board').off('click.elkarte');
1415
	});
1416
1417
	$('.edit_board').show().on('click.elkarte', function(e) {
1418
		var $icon = $(this),
1419
			board_id = $icon.data('boardid'),
1420
			board_profile = $icon.data('boardprofile'),
1421
			$target = $('#edit_board_' + board_id),
1422
			$select = $('<select />')
1423
				.attr('name', 'boardprofile[' + board_id + ']')
1424
				.change(function() {
1425
					$(this).find('option:selected').each(function() {
1426
						if ($(this).attr('value') == board_profile)
1427
							$icon.addClass('nochanges').removeClass('changed');
1428
						else
1429
							$icon.addClass('changed').removeClass('nochanges');
1430
					});
1431
				});
1432
1433
		e.preventDefault();
1434
		$(permission_profiles).each(function(key, value) {
1435
			var $opt = $('<option />').attr('value', value.id).text(value.name);
1436
1437
			if (value.id == board_profile)
1438
				$opt.attr('selected', 'selected');
1439
1440
			$select.append($opt);
1441
		});
1442
1443
		$target.replaceWith($select);
1444
		$select.change();
1445
1446
		$('.edit_all_board_profiles').replaceWith($('<input type="submit" class="right_submit" />')
1447
			.attr('name', 'save_changes')
1448
			.attr('value', txt_save)
1449
		);
1450
		$icon.off('click.elkarte').on('click', function(e) {
1451
			e.preventDefault();
1452
			if ($(this).hasClass('changed'))
1453
				$('input[name="save_changes"]').off('click');
1454
		});
1455
	});
1456
}
1457
1458
/**
1459
 * Creates the image and attaches the event to convert the name of the permission
1460
 * profile into an input to change its name and back.
1461
 *
1462
 * It also removes the "Rename all" and "Remove Selected" buttons
1463
 * and the "Delete" column for consistency
1464
 */
1465
function initEditPermissionProfiles()
1466
{
1467
	// We need a variable to be sure we are going to create only 1 cancel button
1468
	var run_once = false;
1469
1470
	$('.rename_profile').each(function() {
1471
		var $this_profile = $(this);
1472
1473
		$this_profile.after($('<a class="js-ed edit_board" />').attr('href', '#').on('click', function(ev) {
1474
			ev.preventDefault();
1475
1476
			// If we have already created the cancel let's skip it
1477
			if (!run_once)
1478
			{
1479
				var $cancel;
1480
1481
				run_once = true;
1482
				$cancel = $('<a class="js-ed-rm linkbutton" />').on('click', function(ev) {
1483
					ev.preventDefault();
1484
1485
					// js-ed is hopefully a class introduced by this function only
1486
					// Any element with this class will be restored when cancel is clicked
1487
					$('.js-ed').show();
1488
1489
					// js-ed-rm is again a class introduced by this function
1490
					// Any element with this class will be removed when cancelling
1491
					$('.js-ed-rm').remove();
1492
1493
					// The cancel button is removed as well,
1494
					// so we need to generate it again later (if we need it again)
1495
					run_once = false;
1496
1497
					$('#rename').val(txt_permissions_profile_rename);
1498
				}).text(ajax_notification_cancel_text).attr('href', '#');
1499
			}
1500
1501
			$this_profile.after($('<input type="text" class="js-ed-rm input_text" />')
1502
				.attr('name', 'rename_profile[' + $this_profile.data('pid') + ']')
1503
				.val($this_profile.text()));
1504
1505
			// These will have to pop back hitting cancel, so let's prepare them
1506
			$('#rename').addClass('js-ed').val(txt_permissions_commit).before($cancel);
0 ignored issues
show
Bug introduced by
The variable $cancel seems to be used out of scope.

This error can usually be fixed by declaring the variable in the scope where it is used:

function someFunction() {
    (function() {
        var i = 0;
    })();

    // i is not defined.
    alert(i);
}

// This can be fixed by moving the var statement to the outer scope.

function someFunction() {
    var i;
    (function() {
        i = 1;
    })();

    alert(i);
};
Loading history...
1507
			$this_profile.addClass('js-ed').hide();
1508
			$('#delete').addClass('js-ed').hide();
1509
			$('.perm_profile_delete').addClass('js-ed').hide();
1510
			$(this).hide();
1511
		}));
1512
	});
1513
}
1514
1515
/**
1516
 * Attach the AJAX handling of things to the various themes to remove
1517
 * Used in ManageThemes (template_list_themes)
1518
 */
1519
function initDeleteThemes()
1520
{
1521
	$(".delete_theme").on("click", function (event) {
1522
		event.preventDefault();
1523
		var theme_id = $(this).data("theme_id"),
1524
			base_url = $(this).attr("href"),
1525
			pattern = new RegExp(elk_session_var + "=" + elk_session_id + ";(.*)$"),
1526
			tokens = pattern.exec(base_url)[1].split("="),
1527
			token = tokens[1],
1528
			token_var = tokens[0];
1529
1530
		if (confirm(txt_theme_remove_confirm))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1531
		{
1532
			$.ajax({
1533
				type: "GET",
1534
				url: base_url + ";api;xml",
1535
				beforeSend: ajax_indicator(true)
1536
			})
1537
			.done(function(request) {
1538
				if ($(request).find("error").length === 0)
1539
				{
1540
					var new_token = $(request).find("token").text(),
1541
						new_token_var = $(request).find("token_var").text();
1542
1543
					$(".theme_" + theme_id).slideToggle("slow", function () {
1544
						$(this).remove();
1545
					});
1546
1547
					$(".delete_theme").each(function () {
1548
						$(this).attr("href", $(this).attr("href").replace(token_var + "=" + token, new_token_var + "=" + new_token));
1549
					});
1550
				}
1551
				// @todo improve error handling
1552
				else
1553
				{
1554
					alert($(request).find("text").text());
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1555
					// Redirect to the delete theme page, though it will result in a token verification error
1556
					window.location = base_url;
1557
				}
1558
			})
1559
			.fail(function(request) {
0 ignored issues
show
Unused Code introduced by
The parameter request is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1560
				window.location = base_url;
1561
			})
1562
			.always(function() {
1563
				// turn off the indicator
1564
				ajax_indicator(false);
1565
			});
1566
		}
1567
	});
1568
}
1569
1570
/**
1571
 * These two functions (navigatePreview and refreshPreview) are used in ManageThemes
1572
 * (template_edit_style) to create a preview of the site with the changed stylesheets
1573
 *
1574
 * @param {string} url
1575
 */
1576
function navigatePreview(url)
1577
{
1578
	var myDoc = new XMLHttpRequest();
1579
1580
	myDoc.onreadystatechange = function ()
1581
	{
1582
		if (myDoc.readyState !== 4)
1583
			return;
1584
1585
		if (myDoc.responseText !== null && myDoc.status === 200)
1586
		{
1587
			previewData = myDoc.responseText;
1588
			document.getElementById('css_preview_box').style.display = "block";
1589
1590
			// Revert to the theme they actually use ;).
1591
			var tempImage = new Image();
1592
			tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=admin;area=theme;sa=edit;theme=' + theme_id + ';preview;' + (new Date().getTime());
1593
1594
			refreshPreviewCache = null;
1595
			refreshPreview(false);
1596
		}
1597
	};
1598
1599
	var anchor = "";
1600
	if (url.indexOf("#") !== -1)
1601
	{
1602
		anchor = url.substr(url.indexOf("#"));
1603
		url = url.substr(0, url.indexOf("#"));
1604
	}
1605
1606
	myDoc.open("GET", url + (url.indexOf("?") === -1 ? "?" : ";") + 'theme=' + theme_id + anchor, true);
1607
	myDoc.send(null);
1608
}
1609
1610
/**
1611
 * Used when editing a stylesheet.  Allows for the preview to be updated to reflect
1612
 * changes made to the css in the editor.
1613
 *
1614
 * @param {boolean} check
1615
 */
1616
function refreshPreview(check)
1617
{
1618
	var identical = document.forms.stylesheetForm.entire_file.value == refreshPreviewCache;
1619
1620
	// Don't reflow the whole thing if nothing changed!!
1621
	if (check && identical)
1622
		return;
1623
1624
	refreshPreviewCache = document.forms.stylesheetForm.entire_file.value;
1625
1626
	// Replace the paths for images.
1627
	refreshPreviewCache = refreshPreviewCache.replace(/url\(\.\.\/images/gi, "url(" + elk_images_url);
1628
1629
	// Try to do it without a complete reparse.
1630
	if (identical)
1631
	{
1632
		try
1633
		{
1634
			if (is_ie)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable is_ie is declared in the current environment, consider using typeof is_ie === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
1635
			{
1636
				var sheets = frames['css_preview_box'].document.styleSheets;
0 ignored issues
show
Coding Style introduced by
['css_preview_box'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1637
				for (var j = 0; j < sheets.length; j++)
1638
				{
1639
					if (sheets[j].id === 'css_preview_box')
1640
						sheets[j].cssText = document.forms.stylesheetForm.entire_file.value;
1641
				}
1642
			}
1643
			else
1644
			{
1645
				frames['css_preview_box'].document.getElementById("css_preview_sheet").innerHTML = document.forms.stylesheetForm.entire_file.value;
0 ignored issues
show
Coding Style introduced by
['css_preview_box'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1646
			}
1647
		}
1648
		catch (e)
1649
		{
1650
			identical = false;
1651
		}
1652
	}
1653
1654
	// This will work most of the time... could be done with an after-apply, maybe.
1655
	if (!identical)
1656
	{
1657
		var data = previewData,
1658
			preview_sheet = document.forms.stylesheetForm.entire_file.value,
1659
			stylesheetMatch = new RegExp('<link rel="stylesheet"[^>]+href="[^"]+' + editFilename + '[^>]*>'),
1660
			iframe;
1661
1662
		// Replace the paths for images.
1663
		preview_sheet = preview_sheet.replace(/url\(\.\.\/images/gi, "url(" + elk_images_url);
1664
		data = data.replace(stylesheetMatch, '<style type="text/css" id="css_preview_sheet">' + preview_sheet + "<" + "/style>");
1665
1666
		iframe = document.getElementById("css_preview_box");
1667
		iframe.contentWindow.document.open();
1668
		iframe.contentWindow.document.write(data);
1669
		iframe.contentWindow.document.close();
1670
1671
		// Next, fix all its links so we can handle them and reapply the new css!
1672
		iframe.onload = function ()
1673
		{
1674
			var fixLinks = frames["css_preview_box"].document.getElementsByTagName("a");
0 ignored issues
show
Coding Style introduced by
['css_preview_box'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1675
			for (var i = 0; i < fixLinks.length; i++)
1676
			{
1677
				if (fixLinks[i].onclick)
1678
					continue;
1679
1680
				fixLinks[i].onclick = function ()
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1681
				{
1682
					window.parent.navigatePreview(this.href);
1683
					return false;
1684
				};
1685
			}
1686
		};
1687
	}
1688
}
1689
1690
/**
1691
 * Callback (onBeforeUpdate) used by the AutoSuggest, used when adding new bans
1692
 *
1693
 * @param {object} oAutoSuggest
1694
 */
1695
function onUpdateName(oAutoSuggest)
0 ignored issues
show
Unused Code introduced by
The parameter oAutoSuggest is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1696
{
1697
	document.getElementById('user_check').checked = true;
1698
	return true;
1699
}
1700
1701
/**
1702
 * Validates that the ban form is filled out properly before submitting
1703
 * Used when editing bans
1704
 *
1705
 * @param {object} aForm this form object to check
1706
 */
1707
function confirmBan(aForm)
1708
{
1709
	if (aForm.ban_name.value === '')
1710
	{
1711
		alert(txt_ban_name_empty);
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1712
		return false;
1713
	}
1714
1715
	if (aForm.partial_ban.checked && !(aForm.cannot_post.checked || aForm.cannot_register.checked || aForm.cannot_login.checked))
1716
	{
1717
		alert(txt_ban_restriction_empty);
1718
		return false;
1719
	}
1720
1721
	return true;
1722
}
1723
1724
// Enable/disable some fields when working with bans.
1725
var fUpdateStatus = function ()
1726
{
1727
	document.getElementById("expire_date").disabled = !document.getElementById("expires_one_day").checked;
1728
	document.getElementById("cannot_post").disabled = document.getElementById("full_ban").checked;
1729
	document.getElementById("cannot_register").disabled = document.getElementById("full_ban").checked;
1730
	document.getElementById("cannot_login").disabled = document.getElementById("full_ban").checked;
1731
};
1732
1733
/**
1734
 * Used when setting up subscriptions, used to toggle the currency code divs
1735
 * based on which currencies are chosen.
1736
 */
1737
function toggleCurrencyOther()
1738
{
1739
	var otherOn = document.getElementById("paid_currency").value === 'other',
1740
		currencydd = document.getElementById("custom_currency_code_div_dd");
1741
1742
	if (otherOn)
1743
	{
1744
		document.getElementById("custom_currency_code_div").style.display = "";
1745
		document.getElementById("custom_currency_symbol_div").style.display = "";
1746
1747
		if (currencydd)
1748
		{
1749
			document.getElementById("custom_currency_code_div_dd").style.display = "";
1750
			document.getElementById("custom_currency_symbol_div_dd").style.display = "";
1751
		}
1752
	}
1753
	else
1754
	{
1755
		document.getElementById("custom_currency_code_div").style.display = "none";
1756
		document.getElementById("custom_currency_symbol_div").style.display = "none";
1757
1758
		if (currencydd)
1759
		{
1760
			document.getElementById("custom_currency_symbol_div_dd").style.display = "none";
1761
			document.getElementById("custom_currency_code_div_dd").style.display = "none";
1762
		}
1763
	}
1764
}
1765
1766
/**
1767
 * Used to ajax-ively preview the templates of bounced emails (template_bounce_template)
1768
 */
1769
function ajax_getEmailTemplatePreview()
1770
{
1771
	$.ajax({
1772
		type: "POST",
1773
		url: elk_scripturl + "?action=xmlpreview;xml",
1774
		data: {
1775
			item: "bounce_preview",
1776
			title: $("#template_title").val(),
1777
			body: $("#template_body").val()
1778
		},
1779
		context: document.body
1780
	})
1781
	.done(function(request) {
1782
		// Show the preview section, populated with the response
1783
		$("#preview_section").css({display: "block"});
1784
		$("#preview_body").html($(request).find('body').text());
1785
		$("#preview_subject").html($(request).find('subject').text());
1786
1787
		// Any error we need to let them know about?
1788
		if ($(request).find("error").text() !== '')
1789
		{
1790
			var errors_html = '',
1791
				$_errors = $("#errors"),
1792
				errors;
1793
1794
			// Build the error string
1795
			errors = $(request).find('error').each(function() {
0 ignored issues
show
Unused Code introduced by
The variable errors seems to be never used. Consider removing it.
Loading history...
1796
				errors_html += $(this).text() + '<br />';
1797
			});
1798
1799
			// Add it to the error div, set the class level, and show it
1800
			$(document).find("#error_list").html(errors_html);
1801
			$_errors.css({display: ""});
1802
			$_errors.attr('class', parseInt($(request).find('errors').attr('serious')) === 0 ? 'warningbox' : 'errorbox');
1803
		}
1804
		else
1805
		{
1806
			$("#errors").css({display: "none"});
1807
			$("#error_list").html('');
1808
		}
1809
1810
		// Navigate to the preview
1811
		$('html, body').animate({ scrollTop: $('#preview_section').offset().top }, 'slow');
1812
1813
		return false;
1814
	});
1815
1816
	return false;
1817
}
1818
1819
/**
1820
 * Used to ajax-ively preview a word censor
1821
 * Does no checking, it either gets a result or does nothing
1822
 */
1823
function ajax_getCensorPreview()
1824
{
1825
	$.ajax({
1826
		type: 'POST',
1827
		dataType: 'json',
1828
		url: elk_scripturl + "?action=admin;area=postsettings;sa=censor;xml",
1829
		data: {
1830
			censortest: $("#censortest").val()
1831
		}
1832
	})
1833
	.done(function(request) {
1834
		if (request.result === true) {
1835
			// Show the censored text section, populated with the response
1836
			$("#censor_result").css({display: "block"}).html(request.censor);
1837
1838
			// Update the token
1839
			$("#token").attr({name:request.token_val, value:request.token});
1840
1841
			// Clear the box
1842
			$('#censortest').attr({value:''}).val('');
1843
		}
1844
	});
1845
1846
	return false;
1847
}
1848
1849
/**
1850
 * Used to show/hide sub options for the various notifications
1851
 * action=admin;area=featuresettings;sa=mention
1852
 */
1853
$(function() {
1854
	var $headers = $("#mention").find("input[id^='notifications'][id$='[notification]']");
1855
1856
	$headers.change(function() {
1857
		var $top = $(this).closest('dl'),
1858
			$hparent = $(this).parent();
1859
1860
		if (this.checked)
1861
		{
1862
			$top.find('dt:not(:first-child)').fadeIn();
1863
			$top.find('dd:not(:nth-child(2))').each(function() {
1864
				$(this).fadeIn();
1865
				$(this).find('input').prop('disabled', false);
1866
			});
1867
		}
1868
		else
1869
		{
1870
			$top.find('dt:not(:first-child)').hide();
1871
			$top.find('dd:not(:nth-child(2))').each(function() {
1872
				$(this).hide();
1873
				$(this).find('input').prop('disabled', true);
1874
			});
1875
		}
1876
1877
		$hparent.show();
1878
		$hparent.prev().show();
1879
	});
1880
1881
	$headers.change();
1882
});
1883
1884
/**
1885
 * Ajax function to clear CSS and JS hives.  Called from action=admin;area=featuresettings;sa=basic
1886
 * Remove Hives button.
1887
 */
1888
$(function() {
1889
	$('#clean_hives').on('click', function () {
1890
		var infoBar = new ElkInfoBar('bar_clean_hives');
1891
1892
		$.ajax({
1893
			type: 'POST',
1894
			dataType: 'json',
1895
			url: elk_scripturl + "?action=admin;area=featuresettings;sa=basic;xml;api=json",
1896
			data: {
1897
				cleanhives: true
1898
			}
1899
		})
1900
		.done(function(request) {
1901
			infoBar.changeText(request.response);
1902
1903
			if (request.success === true) {
1904
				infoBar.isSuccess();
1905
			}
1906
			else {
1907
				infoBar.isError();
1908
			}
1909
		})
1910
		.fail(function(request) {
0 ignored issues
show
Unused Code introduced by
The parameter request is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1911
			infoBar.isError();
1912
			infoBar.changeText(txt_invalid_response);
1913
		})
1914
		.always(function(request) {
0 ignored issues
show
Unused Code introduced by
The parameter request is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1915
			infoBar.showBar();
1916
		});
1917
1918
		return false;
1919
	});
1920
});
1921
1922
/**
1923
 * Enable / disable "core" features of the software. Called from action=admin;area=corefeatures
1924
 */
1925
$(function() {
1926
	if ($('#core_features').length === 0)
1927
	{
1928
		return;
1929
	}
1930
1931
	$(".core_features_hide").css('display', 'none');
1932
	$(".core_features_img").show().css({'cursor': 'pointer'}).each(function() {
1933
		var sImageText = $(this).hasClass('on') ? feature_on_text : feature_off_text;
1934
		$(this).attr({ title: sImageText, alt: sImageText });
1935
	});
1936
	$("#core_features_submit").css('display', 'none');
1937
1938
	if (!token_name)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable token_name is declared in the current environment, consider using typeof token_name === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
1939
		token_name = $("#core_features_token").attr("name");
0 ignored issues
show
Bug introduced by
The variable token_name seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_name.
Loading history...
1940
1941
	if (!token_value)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable token_value is declared in the current environment, consider using typeof token_value === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
1942
		token_value = $("#core_features_token").attr("value");
0 ignored issues
show
Bug introduced by
The variable token_value seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_value.
Loading history...
1943
1944
	// Attach our action to the core features power button
1945
	$(".core_features_img").click(function() {
1946
		var cc = $(this),
1947
			cf = $(this).attr("id").substring(7),
1948
			imgs = new Array(elk_images_url + "/admin/switch_off.png", elk_images_url + "/admin/switch_on.png"),
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
1949
			new_state = !$("#feature_" + cf).attr("checked"),
1950
			ajax_infobar = new ElkInfoBar('core_features_bar', {error_class: 'errorbox', success_class: 'successbox'}),
1951
			data;
1952
1953
		$("#feature_" + cf).attr("checked", new_state);
1954
1955
		data = {save: "save", feature_id: cf};
1956
		data[$("#core_features_session").attr("name")] = $("#core_features_session").val();
1957
		data[token_name] = token_value;
1958
1959
		$(".core_features_status_box").each(function(){
1960
			data[$(this).attr("name")] = !$(this).attr("checked") ? 0 : 1;
1961
		});
1962
1963
		// Launch AJAX request.
1964
		$.ajax({
1965
			// The link we are accessing.
1966
			url: elk_scripturl + "?action=xmlhttp;sa=corefeatures;xml",
1967
1968
			// The type of request.
1969
			type: "post",
1970
1971
			// The type of data that is getting returned.
1972
			data: data
1973
		})
1974
		.done(function(request) {
1975
			if ($(request).find("errors").find("error").length !== 0)
1976
			{
1977
				ajax_infobar.isError();
1978
				ajax_infobar.changeText($(request).find("errors").find("error").text()).showBar();
1979
			}
1980
			else if ($(request).find("elk").length !== 0)
1981
			{
1982
				$("#feature_link_" + cf).html($(request).find("corefeatures").find("corefeature").text());
1983
				cc.attr({
1984
					"src": imgs[new_state ? 1 : 0],
1985
					"title": new_state ? feature_on_text : feature_off_text,
1986
					"alt": new_state ? feature_on_text : feature_off_text
1987
				});
1988
				$("#feature_link_" + cf).fadeOut().fadeIn();
1989
				ajax_infobar.isSuccess();
1990
				var message = $(request).find("messages").find("message").text();
1991
				ajax_infobar.changeText(message).showBar();
1992
1993
				token_name = $(request).find("tokens").find('[type="token"]').text();
0 ignored issues
show
Bug introduced by
The variable token_name seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_name.
Loading history...
1994
				token_value = $(request).find("tokens").find('[type="token_var"]').text();
0 ignored issues
show
Bug introduced by
The variable token_value seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_value.
Loading history...
1995
			}
1996
			else
1997
			{
1998
				ajax_infobar.isError();
1999
				ajax_infobar.changeText(core_settings_generic_error).showBar();
2000
			}
2001
		})
2002
		.fail(function(error) {
2003
			ajax_infobar.changeText(error).showBar();
2004
		});
2005
	});
2006
});
2007
2008
function confirmAgreement(text) {
2009
	if ($('#checkboxAcceptAgreement').is(':checked')) {
2010
		return confirm(text);
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
2011
	}
2012
	return true;
2013
}
2014